package dq.study.designmodel.proxy.dynamic;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Iterator;

/**
 * 手写jdk动态代理实现
 *
 * @author dongqun
 * @Description:
 * @date 2019/3/31 21:48
 */
public class Proxy {

    public static Object newProxyInstance(Class cls, InvokeHandler invokeHandler) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 动态生成Java文件
        String fileName = generateAndWriteJavaFile(cls);
        // 编译
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        Iterable units = fileManager.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, units);
        task.call();
        // 加载
        URL[] url = new URL[]{new URL("file:/" + System.getProperty("user.dir") + "/proxy/src/")};
        URLClassLoader loader = new URLClassLoader(url);
        Class cls1 = loader.loadClass("dq.study.designmodel.proxy.dynamic.$Proxy1");
        Constructor constructor = cls1.getConstructor(InvokeHandler.class);
        return constructor.newInstance(invokeHandler);
    }

    private static String generateAndWriteJavaFile(Class cls) throws IOException {
        String methodStr = "";
        String rt = "\n\t";
        Method[] methods = cls.getMethods();
        // 获取目标类的所有方法
        for (Method method : methods) {
            methodStr += "@Override" + rt +
                    "public void " + method.getName() + "(){" + rt +
                    "  try{" + rt +
                    "      Method method = " + cls.getName() + ".class.getMethod(\"" + method.getName() + "\");" + rt +
                    "      h.invoke(this,method);" + rt +
                    "      }catch(Exception e){e.printStackTrace();}" + rt +
                    "}" + rt;
        }

        // 按照jdk规定格式生成代理类
        String src =
                "package dq.study.designmodel.proxy.dynamic;" + rt +
                        "import java.lang.reflect.*;" + rt +
                        "public class $Proxy1 implements " + cls.getName() + "{" + rt +
                        "   public $Proxy1(InvokeHandler handler){" + rt +
                        "       this.h = handler;" + rt +
                        "   }" + rt +
                        "   dq.study.designmodel.proxy.dynamic.InvokeHandler h;" + rt +
                        methodStr + rt +
                        "}" + rt;

        // 将生成的代理类写到指定路径
        String fileName = System.getProperty("user.dir") + "/proxy/src/dq/study/designmodel/proxy/dynamic/$Proxy1.java";
        File file = new File(fileName);
        FileWriter writer = new FileWriter(file);
        writer.write(src);
        writer.flush();
        writer.close();
        return fileName;
    }

}
